# -*- coding: utf-8 -*-
# @Time    : 2024/7/17 17:48
# @Author  : yujiahao
# @File    : 39_fastapi_sql_schemas.py
# @description:SQL (关系型) 数据库 创建 Pydantic 模型

"""
Tip:

为了避免 SQLAlchemy 模型和 Pydantic 模型之间的混淆，我们将有 38_fastapi_sql_models.py（SQLAlchemy 模型的文件）和 39_fastapi_sql_schemas.py（Pydantic 模型的文件）。

这些 Pydantic 模型或多或少地定义了一个“schema”（一个有效的数据形状）。

因此，这将帮助我们在使用两者时避免混淆。

创建初始 Pydantic 模型/模式：

创建一个 ItemBase 和 UserBase Pydantic 模型（或者我们说“schema”），他们拥有创建或读取数据时具有的共同属性。

然后创建一个继承自他们的 ItemCreate 和 UserCreate，并添加创建时所需的其他数据（或属性）。

在创建 UserCreate 时，必须包含一个 password 属性。

但是为了安全起见，password 不会出现在其他同类 Pydantic 模型中，例如通过 API 读取一个用户数据时，它不应当包含在内。


【SQLAlchemy 风格和 Pydantic 风格】

请注意，SQLAlchemy 模型使用 '=' 来定义属性，并将类型作为参数传递给 Column，例如：

    name = Column(String)

而 Pydantic 模型使用 ':' 声明类型，新的类型注释语法/类型提示是：

    name: str

请牢记这一点，这样您在使用 ':' 还是 '=' 时就不会感到困惑。

"""

# todo 0、导入pydantic依赖
from pydantic import BaseModel


# todo 1、创建初始 Pydantic模型/模式
class ItemBase(BaseModel):
    title: str
    description: str | None = None


# todo 2、创建初始 Pydantic模型/模式
class ItemCreate(ItemBase):
    pass


# todo 1、创建用于读取/返回的Pydantic模型/模式
# 请注意，读取用户（从 API 返回）时将使用不包括password的User Pydantic模型。


class Item(ItemBase):
    id: int
    owner_id: int

    # todo 1、使用 Pydantic 的orm_mode
    """
    现在，在用于查询的 Pydantic 模型 Item 和 User 中，添加一个内部 Config 类。

    此类 Config 用于为 Pydantic 提供配置。

    在 Config 类中，设置属性 orm_mode = True。

    Config 类及其选项（如 orm_mode）在 Pydantic 模型中是非常有用的配置工具。
    启用 orm_mode 后，Pydantic 模型可以与 ORM 对象（如 SQLAlchemy 模型）无缝集成。
    这使得在处理数据库查询结果时更加方便和高效。

    Pydantic 的 orm_mode 将告诉 Pydantic 模型读取数据，即它不是一个 dict，而是一个 ORM 模型（或任何其他具有属性的任意对象）。

    这样，而不是仅仅试图从 dict 上获取值，如下所示：

        id = data["id"]

    它还会尝试从属性中获取它，如：

        id = data.id

    有了这个，Pydantic 模型与 ORM 兼容，您只需在路径操作的 response_model 参数中声明它即可。

    您将能够返回一个数据库模型，它将从中读取数据。
    
    

    ORM 模式的技术细节：

    SQLAlchemy 和许多其他 ORM 默认情况下是“延迟加载”。

    这意味着，例如，除非您尝试访问包含该数据的属性，否则它们不会从数据库中获取关系数据。

    例如，访问属性 items：

        current_user.items

    将使 SQLAlchemy 转到 items 表并获取该用户的项目，在调用 .items 之前不会去查询数据库。

    没有 orm_mode，如果您从路径操作返回一个 SQLAlchemy 模型，它不会包含关系数据。

    即使您在 Pydantic 模型中声明了这些关系，也没有用处。

    但是在 ORM 模式下，由于 Pydantic 本身会尝试从属性访问它需要的数据（而不是假设为 dict），你可以声明你想要返回的特定数据，它甚至可以从 ORM 中获取它。
    """

    class Config:
        orm_mode = True


# todo 3、创建初始 Pydantic模型/模式
class UserBase(BaseModel):
    email: str


# todo 4、创建一个 Pydantic模型
class UserCreate(UserBase):
    password: str


# todo 2、创建用于读取/返回的Pydantic模型/模式
class User(UserBase):
    id: int
    is_active: bool
    items: list[Item] = []
    # todo 2、使用 Pydantic 的orm_mode
    """
    请注意，它使用=分配一个值，例如：orm_mode = True
    
    它不使用之前的:来类型声明。
    
    这是设置配置值，而不是声明类型。
    """
    class Config:
        orm_mode = True
